#include <assert.h>

#include "matrix_algorithms.h"

Bubble *newBubble(int colour) {
  Bubble *bubble = (Bubble *) malloc(sizeof(Bubble));
  assert(bubble != NULL);
  bubble->colour = colour;
  bubble->wasVerifiedForPop = 0; 
  bubble->wasVerifiedForFall = 0; 
  bubble->willPop = 0; 
  bubble->willFall = 0; 
  return bubble;
}

 
Bubble* newBubbleEmpty () {
  Bubble *bubble = (Bubble *) malloc(sizeof(Bubble));
  assert(bubble != NULL);
  bubble->colour = -1;
  bubble->wasVerifiedForPop = 1;
  bubble->wasVerifiedForFall = 1; 
  bubble->willPop = 0;
  bubble->willFall = 0;
  return bubble;
}

void checkIfColorMatches(Bubble ***bubbleMatrix, int height, int width, int col, int row, int colourToCheck, int *matchCount) {
	if (row >= height || row < 0 || col >= width || col < 0)
		return;
	if ((*bubbleMatrix)[row * width + col]->wasVerifiedForPop)
		return;
    
	(*bubbleMatrix)[row * width + col]->wasVerifiedForPop = 1;
	if ((*bubbleMatrix)[row * width + col]->colour == colourToCheck) {
		++(*matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col - 2, row, colourToCheck, matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col + 2, row, colourToCheck, matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col + 1, row - 1, colourToCheck, matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col + 1, row + 1, colourToCheck, matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col - 1, row - 1, colourToCheck, matchCount);
		checkIfColorMatches (bubbleMatrix, height, width, col + 1, row + 1, colourToCheck, matchCount);
	}
	else
		return;
    
	if (*matchCount >= 3) {
		(*bubbleMatrix)[row * width + col]->willPop = 1;
	}
}

int hasConnectionToTop(Bubble ***bubbleMatrix, int height, int width, int col, int row) {
	if (row >= height || row < 0 || col >= width || col < 0)
		return 0;
	if ((*bubbleMatrix)[row * width + col]->willPop)
		return 0;
	if ((*bubbleMatrix)[row * width + col]->colour == -1)
		return 0;
	if (row == 0)
		return 1;
	if ((*bubbleMatrix)[row * width + col]->wasVerifiedForFall)
		return 0;
	(*bubbleMatrix)[row * width + col]->wasVerifiedForFall = 1;
	(*bubbleMatrix)[row * width + col]->willFall = !(hasConnectionToTop (bubbleMatrix, height, width, col + 1, row - 1)
			    || hasConnectionToTop (bubbleMatrix, height, width, col - 1, row - 1) ||
				hasConnectionToTop(bubbleMatrix, height, width, col + 2, row) || hasConnectionToTop (bubbleMatrix, height, width, col - 2, row) ||
				hasConnectionToTop(bubbleMatrix, height, width, col + 1, row + 1) || hasConnectionToTop(bubbleMatrix, height, width, col - 1, row + 1));
	
  (*bubbleMatrix)[row * width + col]->wasVerifiedForFall = 0;
	
  return !((*bubbleMatrix)[row * width + col]->willFall);
}

void pop(Bubble ***bubbleMatrix, int height, int width, int startCol, int startRow) {
	if (startRow >= height || startRow < 0 || startCol >= width || startCol < 0)
		return;
	if ((*bubbleMatrix)[startRow * width + startCol]->willPop == 0)
		return;
    
	(*bubbleMatrix)[startRow * width + startCol]->willPop = 0;
  
	pop(bubbleMatrix, height, width, startCol + 2, startRow);
	pop(bubbleMatrix, height, width, startCol - 2, startRow);
	pop(bubbleMatrix, height, width, startCol + 1, startRow + 1);
	pop(bubbleMatrix, height, width, startCol + 1, startRow - 1);
	pop(bubbleMatrix, height, width, startCol - 1, startRow + 1);
	pop(bubbleMatrix, height, width, startCol - 1, startRow - 1);
  
	(*bubbleMatrix)[startRow * width + startCol] = newBubbleEmpty();
}

void checkForPop(Bubble ***bubbleMatrix, int height, int width, int newBubbleCol, int newBubbleRow, Bubble *newBubble) {
  int i,j;
	newBubble->wasVerifiedForPop = 1;
	int matchCount = 1;
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol - 2, newBubbleRow, newBubble->colour, &matchCount);
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol + 2, newBubbleRow, newBubble->colour, &matchCount);
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol + 1, newBubbleRow - 1, newBubble->colour, &matchCount);
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol + 1, newBubbleRow + 1, newBubble->colour, &matchCount);
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol - 1, newBubbleRow - 1, newBubble->colour, &matchCount);
	checkIfColorMatches (bubbleMatrix, height, width, newBubbleCol + 1, newBubbleRow + 1, newBubble->colour, &matchCount);

	if (matchCount >= 3) {
		pop(bubbleMatrix, height, width, newBubbleCol - 2, newBubbleRow);
		pop(bubbleMatrix, height, width, newBubbleCol + 2, newBubbleRow);
		pop(bubbleMatrix, height, width, newBubbleCol + 1, newBubbleRow + 1);
		pop(bubbleMatrix, height, width, newBubbleCol + 1, newBubbleRow - 1);
		pop(bubbleMatrix, height, width, newBubbleCol - 1, newBubbleRow + 1);
		pop(bubbleMatrix, height, width, newBubbleCol - 1, newBubbleRow - 1);
		
    for (i = (height - 1); i > 0; --i)
				for (j = 0; j < width; ++j) {
					if ((*bubbleMatrix)[i * width + j]->colour != -1 && !((*bubbleMatrix)[i * width + j]->wasVerifiedForFall))
						hasConnectionToTop(bubbleMatrix, height, width, j, i);
					if ((*bubbleMatrix)[i * width + j]->willFall)
						(*bubbleMatrix)[i * width + j] = newBubbleEmpty();
				}
	}
	else
		(*bubbleMatrix)[newBubbleRow * width + newBubbleCol] = newBubble;
    
	for (i = 0; i < height;++i)
		for (j = 0; j < width; ++j) {
			(*bubbleMatrix)[i * width + j]->wasVerifiedForFall = 0;
			(*bubbleMatrix)[i * width + j]->wasVerifiedForPop = 0;
		}
}

void printMatrixForDebug(Bubble ***bubbleMatrix, int height, int width) {
  int y, x;
  for (y = 0; y < height; ++y) {
    for (x = 0; x < width; ++x)
      printf("%d", (*bubbleMatrix)[y * width + x]->colour);
    printf ("\n");
  }
}
